package com.plugin.storage.storage.aliyun;

import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.comm.Protocol;
import com.aliyun.oss.model.CompleteMultipartUploadResult;
import com.aliyun.oss.model.UploadFileRequest;
import com.aliyun.oss.model.UploadFileResult;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.vod.model.v20170321.*;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.io.BaseEncoding;
import com.plugin.storage.aliyun.AliyunSTS;
import com.plugin.storage.base.AuthToken;
import com.plugin.storage.base.SdkContext;
import com.plugin.storage.base.StorageException;
import com.plugin.storage.storage.JacksonUtils;
import com.plugin.storage.storage.model.PlayVideoReq;
import com.plugin.storage.storage.model.UploadVideo;
import com.plugin.storage.storage.model.UploadVideoReq;
import com.plugin.storage.storage.spi.VideoProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static java.util.stream.Collectors.toMap;

public class AliyunVOD implements VideoProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(AliyunVOD.class);

    @Override
    public UploadVideo.Auth auth(SdkContext sdkContext, UploadVideoReq uploadVideoReq) {
        AuthToken token = AliyunSTS.authToken(sdkContext);
        LOGGER.debug(token.toString());
        IClientProfile profile = DefaultProfile.getProfile(sdkContext.getRegion(), token.getAccessKeyId(), token.getAccessKeySecret());
        DefaultAcsClient client = new DefaultAcsClient(profile);

        CreateUploadVideoRequest request = new CreateUploadVideoRequest();
        request.setProtocol(ProtocolType.HTTPS);
        request.setSecurityToken(token.getSecurityToken());
        request.setTitle(uploadVideoReq.getTitle());
        request.setCoverURL(uploadVideoReq.getCoverUrl());
        request.setDescription(uploadVideoReq.getDescription());
        request.setFileName(uploadVideoReq.getFileName());
        request.setCateId(uploadVideoReq.getCateId());
        request.setTags(uploadVideoReq.getTags());
        request.setTemplateGroupId(uploadVideoReq.getTemplateGroupId());

        try {
            CreateUploadVideoResponse response = client.getAcsResponse(request);
            return new UploadVideo.Auth()
                    .setVideoId(response.getVideoId())
                    .setUploadAddress(response.getUploadAddress())
                    .setUploadAuth(response.getUploadAuth());
        } catch (ClientException e) {
            LOGGER.error(e.getMessage(), e);
            throw new StorageException("视频上传凭证获取失败:" + e.getMessage(), e);
        }
    }

    @Override
    public UploadVideo upload(SdkContext context, UploadVideoReq uploadVideoReq) {
        UploadVideo.Auth auth = auth(context, uploadVideoReq);
        AuthToken token = JacksonUtils.toObject(new String(BaseEncoding.base64().decode(auth.getUploadAuth())), AuthToken.class);
        Address address = JacksonUtils.toObject(new String(BaseEncoding.base64().decode(auth.getUploadAddress())), Address.class);

        UploadFileRequest uploadFileRequest = new UploadFileRequest(address.getBucket(), address.getFileName());
        uploadFileRequest.setUploadFile(uploadVideoReq.getLocalPath());
        // Sets the concurrent upload task number to 5.
        uploadFileRequest.setTaskNum(5);
        // Sets the part size to 1MB.
        uploadFileRequest.setPartSize(1024 * 1024);
        // Enables the checkpoint file. By default it's off.
        uploadFileRequest.setEnableCheckpoint(true);

        ClientBuilderConfiguration configuration = new ClientBuilderConfiguration();
        configuration.setProtocol(Protocol.HTTPS);
        OSS ossClient = new OSSClientBuilder().build(address.getEndpoint(), token.getAccessKeyId(), token.getAccessKeySecret(), token.getSecurityToken(), configuration);

        try {
            UploadFileResult uploadResult = ossClient.uploadFile(uploadFileRequest);
            CompleteMultipartUploadResult result =
                    uploadResult.getMultipartUploadResult();

            LOGGER.debug(result.getLocation());
            return new UploadVideo().setVideoId(auth.getVideoId());
        } catch (Throwable e) {
            LOGGER.error(e.getMessage(), e);
            throw new StorageException("上传失败:" + e.getMessage(), e);
        } finally {
            ossClient.shutdown();
        }
    }

    @Override
    public UploadVideo playAuth(SdkContext sdkContext, PlayVideoReq playVideoReq) {
        AuthToken token = AliyunSTS.authToken(sdkContext);

        IClientProfile profile = DefaultProfile.getProfile(sdkContext.getRegion(), token.getAccessKeyId(), token.getAccessKeySecret());
        DefaultAcsClient client = new DefaultAcsClient(profile);
        GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();

        request.setVideoId(playVideoReq.getVideoId());
        request.setSecurityToken(token.getSecurityToken());
        request.setProtocol(ProtocolType.HTTPS);

        try {
            GetVideoPlayAuthResponse response = client.getAcsResponse(request);
            return new UploadVideo()
                    .setVideoId(playVideoReq.getVideoId())
                    .setPlayAuth(response.getPlayAuth())
                    .setVideoMeta(JacksonUtils.toObject(response.getVideoMeta(), UploadVideo.VideoMeta.class));
        } catch (ClientException e) {
            LOGGER.error(e.getMessage(), e);
            throw new StorageException("视频播放凭证获取失败:" + e.getMessage(), e);
        }
    }

    @Override
    public UploadVideo playInfo(SdkContext sdkContext, PlayVideoReq playVideoReq) {
        AuthToken token = AliyunSTS.authToken(sdkContext);

        IClientProfile profile = DefaultProfile.getProfile(sdkContext.getRegion(), token.getAccessKeyId(), token.getAccessKeySecret());
        DefaultAcsClient client = new DefaultAcsClient(profile);
        GetPlayInfoRequest request = new GetPlayInfoRequest();

        request.setVideoId(playVideoReq.getVideoId());
        request.setSecurityToken(token.getSecurityToken());
        request.setProtocol(ProtocolType.HTTPS);

        try {
            GetPlayInfoResponse response = client.getAcsResponse(request);
            return new UploadVideo()
                    .setVideoId(playVideoReq.getVideoId())
                    .setPlayInfo(response.getPlayInfoList().stream().collect(toMap(e -> e.getDefinition() + "." + e.getFormat(), e -> JacksonUtils.toObject(e, UploadVideo.PlayInfo.class))))
                    .setVideoMeta(JacksonUtils.toObject(response.getVideoBase(), UploadVideo.VideoMeta.class));
        } catch (ClientException e) {
            LOGGER.error(e.getMessage(), e);
            throw new StorageException("视频播放凭证获取失败:" + e.getMessage(), e);
        }
    }

    public static class Address {
        @JsonProperty("Endpoint")
        private String endpoint;

        @JsonProperty("Bucket")
        private String bucket;

        @JsonProperty("FileName")
        private String fileName;

        public String getEndpoint() {
            return endpoint;
        }

        public Address setEndpoint(String endpoint) {
            this.endpoint = endpoint;
            return this;
        }

        public String getBucket() {
            return bucket;
        }

        public Address setBucket(String bucket) {
            this.bucket = bucket;
            return this;
        }

        public String getFileName() {
            return fileName;
        }

        public Address setFileName(String fileName) {
            this.fileName = fileName;
            return this;
        }

        @Override
        public String toString() {
            return "Address{" +
                    "endpoint='" + endpoint + '\'' +
                    ", bucket='" + bucket + '\'' +
                    ", fileName='" + fileName + '\'' +
                    '}';
        }
    }

}
